/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
#ifndef __HPM6E00_PLIC_H
#define __HPM6E00_PLIC_H
#include <stdio.h>
#include <stdint.h>

/* \brief 中断回调函数*/
typedef void (*pfn_irq_handler)(void *p_arg);

/* \brief PLIC 目标模式 */
#define HPM_PLIC_TARGET_M_MODE                    0
#define HPM_PLIC_TARGET_S_MODE                    1

/* \brief 平台集中断控制器优先级寄存器偏移 */
#define HPM_PLIC_PRIORITY_OFFSET                 (0x00000004UL)
/* \brief 平台集中断控制器目标中断寄存器偏移 */
#define HPM_PLIC_TARGETINT_OFFSET                (0x00002000UL)

#define HPM_PLIC_CLAIM_OFFSET                    (0x00200004UL)

#define HPM_PLIC_ENABLE_POS_PER_TARGET            7
#define HPM_PLIC_PRIORITY_POS_PER_SOURCE          2
#define HPM_PLIC_CLAIM_POS_PER_TARGET             12

/* \brief 特性寄存器 */
#define HPM_PLIC_FEATURE_OFFSET                  (0x00000000UL)
#define HPM_PLIC_FEATURE_VECTORED_MODE           (0x2UL)
#define HPM_PLIC_FEATURE_PREEMPTIVE_PRIORITY_IRQ (0x1UL)

/* \brief 使能寄存器，每个目标占用 0x80 */
#define HPM_PLIC_ENABLE_OFFSET                   (0x00002000UL)
#define HPM_PLIC_ENABLE_SHIFT_PER_TARGET          7

/* \brief 优先级阈值寄存器，每个目标占用 0x1000 */
#define HPM_PLIC_THRESHOLD_OFFSET                (0x00200000UL)
#define HPM_PLIC_THRESHOLD_SHIFT_PER_TARGET       12

/* \brief 配置寄存器，每个目标占用 0x1000 */
#define HPM_PLIC_CLAIM_OFFSET                    (0x00200004UL)
#define HPM_PLIC_CLAIM_SHIFT_PER_TARGET           12

/* \brief 中断最大数量*/
#define IRQ_NUM_MAX        161

/* \brief 中断号*/
#define IRQn_GPIO0_A       1                   /* GPIO0_A IRQ */
#define IRQn_GPIO0_B       2                   /* GPIO0_B IRQ */
#define IRQn_GPIO0_C       3                   /* GPIO0_C IRQ */
#define IRQn_GPIO0_D       4                   /* GPIO0_D IRQ */
#define IRQn_GPIO0_E       5                   /* GPIO0_E IRQ */
#define IRQn_GPIO0_F       6                   /* GPIO0_F IRQ */
#define IRQn_GPIO0_V       7                   /* GPIO0_V IRQ */
#define IRQn_GPIO0_W       8                   /* GPIO0_W IRQ */
#define IRQn_GPIO0_X       9                   /* GPIO0_X IRQ */*/
#define IRQn_GPIO0_Y       10                  /* GPIO0_Y IRQ */
#define IRQn_GPIO0_Z       11                  /* GPIO0_Z IRQ */
#define IRQn_GPIO1_A       12                  /* GPIO1_A IRQ */
#define IRQn_GPIO1_B       13                  /* GPIO1_B IRQ */
#define IRQn_GPIO1_C       14                  /* GPIO1_C IRQ */
#define IRQn_GPIO1_D       15                  /* GPIO1_D IRQ */
#define IRQn_GPIO1_E       16                  /* GPIO1_E IRQ */
#define IRQn_GPIO1_F       17                  /* GPIO1_F IRQ */
#define IRQn_GPIO1_V       18                  /* GPIO1_V IRQ */
#define IRQn_GPIO1_W       19                  /* GPIO1_W IRQ */
#define IRQn_GPIO1_X       20                  /* GPIO1_X IRQ */
#define IRQn_GPIO1_Y       21                  /* GPIO1_Y IRQ */
#define IRQn_GPIO1_Z       22                  /* GPIO1_Z IRQ */
#define IRQn_GPTMR0        23                  /* GPTMR0 IRQ */
#define IRQn_GPTMR1        24                  /* GPTMR1 IRQ */
#define IRQn_GPTMR2        25                  /* GPTMR2 IRQ */
#define IRQn_GPTMR3        26                  /* GPTMR3 IRQ */
#define IRQn_GPTMR4        27                  /* GPTMR4 IRQ */
#define IRQn_GPTMR5        28                  /* GPTMR5 IRQ */
#define IRQn_GPTMR6        29                  /* GPTMR6 IRQ */
#define IRQn_GPTMR7        30                  /* GPTMR7 IRQ */
#define IRQn_UART0         31                  /* UART0 IRQ */
#define IRQn_UART1         32                  /* UART1 IRQ */
#define IRQn_UART2         33                  /* UART2 IRQ */
#define IRQn_UART3         34                  /* UART3 IRQ */
#define IRQn_UART4         35                  /* UART4 IRQ */
#define IRQn_UART5         36                  /* UART5 IRQ */
#define IRQn_UART6         37                  /* UART6 IRQ */
#define IRQn_UART7         38                  /* UART7 IRQ */
#define IRQn_I2C0          39                  /* I2C0 IRQ */
#define IRQn_I2C1          40                  /* I2C1 IRQ */
#define IRQn_I2C2          41                  /* I2C2 IRQ */
#define IRQn_I2C3          42                  /* I2C3 IRQ */
#define IRQn_SPI0          43                  /* SPI0 IRQ */
#define IRQn_SPI1          44                  /* SPI1 IRQ */
#define IRQn_SPI2          45                  /* SPI2 IRQ */
#define IRQn_SPI3          46                  /* SPI3 IRQ */
#define IRQn_TSNS          47                  /* TSNS IRQ */
#define IRQn_MBX0A         48                  /* MBX0A IRQ */
#define IRQn_MBX0B         49                  /* MBX0B IRQ */
#define IRQn_MBX1A         50                  /* MBX1A IRQ */
#define IRQn_MBX1B         51                  /* MBX1B IRQ */
#define IRQn_EWDG0         52                  /* EWDG0 IRQ */
#define IRQn_EWDG1         53                  /* EWDG1 IRQ */
#define IRQn_EWDG2         54                  /* EWDG2 IRQ */
#define IRQn_EWDG3         55                  /* EWDG3 IRQ */
#define IRQn_HDMA          56                  /* HDMA IRQ */
#define IRQn_LOBS          57                  /* LOBS IRQ */
#define IRQn_ADC0          58                  /* ADC0 IRQ */
#define IRQn_ADC1          59                  /* ADC1 IRQ */
#define IRQn_ADC2          60                  /* ADC2 IRQ */
#define IRQn_ADC3          61                  /* ADC3 IRQ */
#define IRQn_ACMP_00       62                  /* ACMP0[0] IRQ */
#define IRQn_ACMP_01       63                  /* ACMP0[1] IRQ */
#define IRQn_ACMP_10       64                  /* ACMP1[0] IRQ */
#define IRQn_ACMP_11       65                  /* ACMP1[1] IRQ */
#define IRQn_ACMP_20       66                  /* ACMP2[0] IRQ */
#define IRQn_ACMP_21       67                  /* ACMP2[1] IRQ */
#define IRQn_ACMP_30       68                  /* ACMP3[0] IRQ */
#define IRQn_ACMP_31       69                  /* ACMP3[1] IRQ */
#define IRQn_I2S0          70                  /* I2S0 IRQ */
#define IRQn_I2S1          71                  /* I2S1 IRQ */
#define IRQn_DAO           72                  /* DAO IRQ */
#define IRQn_PDM           73                  /* PDM IRQ */
#define IRQn_UART8         74                  /* UART8 IRQ */
#define IRQn_UART9         75                  /* UART9 IRQ */
#define IRQn_UART10        76                  /* UART10 IRQ */
#define IRQn_UART11        77                  /* UART11 IRQ */
#define IRQn_UART12        78                  /* UART12 IRQ */
#define IRQn_UART13        79                  /* UART13 IRQ */
#define IRQn_UART14        80                  /* UART14 IRQ */
#define IRQn_UART15        81                  /* UART15 IRQ */
#define IRQn_I2C4          82                  /* I2C4 IRQ */
#define IRQn_I2C5          83                  /* I2C5 IRQ */
#define IRQn_I2C6          84                  /* I2C6 IRQ */
#define IRQn_I2C7          85                  /* I2C7 IRQ */
#define IRQn_SPI4          86                  /* SPI4 IRQ */
#define IRQn_SPI5          87                  /* SPI5 IRQ */
#define IRQn_SPI6          88                  /* SPI6 IRQ */
#define IRQn_SPI7          89                  /* SPI7 IRQ */
#define IRQn_MCAN0         90                  /* MCAN0 IRQ */
#define IRQn_MCAN1         91                  /* MCAN1 IRQ */
#define IRQn_MCAN2         92                  /* MCAN2 IRQ */
#define IRQn_MCAN3         93                  /* MCAN3 IRQ */
#define IRQn_MCAN4         94                  /* MCAN4 IRQ */
#define IRQn_MCAN5         95                  /* MCAN5 IRQ */
#define IRQn_MCAN6         96                  /* MCAN6 IRQ */
#define IRQn_MCAN7         97                  /* MCAN7 IRQ */
#define IRQn_PTPC          98                  /* PTPC IRQ */
#define IRQn_QEI0          99                  /* QEI0 IRQ */
#define IRQn_QEI1          100                 /* QEI1 IRQ */
#define IRQn_QEI2          101                 /* QEI2 IRQ */
#define IRQn_QEI3          102                 /* QEI3 IRQ */
#define IRQn_PWM0          103                 /* PWM0 IRQ */
#define IRQn_PWM1          104                 /* PWM1 IRQ */
#define IRQn_PWM2          105                 /* PWM2 IRQ */
#define IRQn_PWM3          106                 /* PWM3 IRQ */
#define IRQn_RDC0          107                 /* RDC0 IRQ */
#define IRQn_RDC1          108                 /* RDC1 IRQ */
#define IRQn_SDM0          109                 /* SDM0 IRQ */
#define IRQn_SDM1          110                 /* SDM1 IRQ */
#define IRQn_SEI_00        111                 /* SEI0[0] IRQ */
#define IRQn_SEI_01        112                 /* SEI0[1] IRQ */
#define IRQn_SEI_02        113                 /* SEI0[2] IRQ */
#define IRQn_SEI_03        114                 /* SEI0[3] IRQ */
#define IRQn_MTG0          115                 /* MTG0 IRQ */
#define IRQn_MTG1          116                 /* MTG1 IRQ */
#define IRQn_VSC0          117                 /* VSC0 IRQ */
#define IRQn_VSC1          118                 /* VSC1 IRQ */
#define IRQn_CLC_00        119                 /* CLC0[0] IRQ */
#define IRQn_CLC_01        120                 /* CLC0[1] IRQ */
#define IRQn_CLC_10        121                 /* CLC1[0] IRQ */
#define IRQn_CLC_11        122                 /* CLC1[1] IRQ */
#define IRQn_TRGMUX0       123                 /* TRGMUX0 IRQ */
#define IRQn_TRGMUX1       124                 /* TRGMUX1 IRQ */
#define IRQn_ENET0         125                 /* ENET0 IRQ */
#define IRQn_NTMR0         126                 /* NTMR0 IRQ */
#define IRQn_USB0          127                 /* USB0 中断 */
#define IRQn_TSW0          128                 /* TSW[0] IRQ */
#define IRQn_TSW1          129                 /* TSW[1] IRQ */
#define IRQn_TSW2          130                 /* TSW[2] IRQ */
#define IRQn_TSW3          131                 /* TSW[3] IRQ */
#define IRQn_TSW_PTP_EVT   132                 /* TSW_PTP_EVT IRQ */
#define IRQn_ESC           133                 /* ESC IRQ */
#define IRQn_ESC_SYNC0     134                 /* ESC_SYNC0 IRQ */
#define IRQn_ESC_SYNC1     135                 /* ESC_SYNC1 IRQ */
#define IRQn_ESC_RESET     136                 /* ESC_RESET IRQ */
#define IRQn_XPI0          137                 /* XPI0 IRQ */
#define IRQn_FEMC          138                 /* FEMC IRQ */
#define IRQn_PPI           139                 /* PPI IRQ */
#define IRQn_XDMA          140                 /* XDMA IRQ */
#define IRQn_FFA           141                 /* FFA IRQ */
#define IRQn_SDP           142                 /* SDP IRQ */
#define IRQn_RNG           143                 /* RNG IRQ */
#define IRQn_PKA           144                 /* PKA IRQ */
#define IRQn_PSEC          145                 /* PSEC IRQ */
#define IRQn_PGPIO         146                 /* PGPIO IRQ */
#define IRQn_PEWDG         147                 /* PEWDG IRQ */
#define IRQn_PTMR          148                 /* PTMR IRQ */
#define IRQn_PUART         149                 /* PUART IRQ */
#define IRQn_FUSE          150                 /* FUSE IRQ */
#define IRQn_SECMON        151                 /* SECMON IRQ */
#define IRQn_RTC           152                 /* RTC IRQ */
#define IRQn_PAD_WAKEUP    153                 /* PAD_WAKEUP IRQ */
#define IRQn_BGPIO         154                 /* BGPIO IRQ */
#define IRQn_BVIO          155                 /* BVIO IRQ */
#define IRQn_BROWNOUT      156                 /* BROWNOUT IRQ */
#define IRQn_SYSCTL        157                 /* SYSCTL IRQ */
#define IRQn_CPU_0         158                 /* CPU0 IRQ */
#define IRQn_CPU_1         159                 /* CPU1 IRQ */
#define IRQn_DEBUG_0       160                 /* DEBUG[0] IRQ */
#define IRQn_DEBUG_1       161                 /* DEBUG[1] IRQ */

/* \brief 中断控制器机器模式中断使能状态 */
#define intc_m_enable_irq(irq)  intc_irq_enable(HPM_PLIC_TARGET_M_MODE, irq)
/* \brief 中断控制器机器模式中断禁能状态 */
#define intc_m_disable_irq(irq) intc_irq_disable(HPM_PLIC_TARGET_M_MODE, irq)

/* \brief PLIC 阈值寄存器与配置寄存器值结构体 */
struct plic_threshold_claim_complete {
    uint32_t threshold_prio;
    uint32_t claim_complete;
};

/**
 * \brief 设置 PLIC（平台级中断控制器） 特性
 *
 * \param[in] base    PLIC 基地址
 * \param[in] feature 要设置的特性
 */
__attribute__((always_inline)) static inline void __plic_set_feature(uint32_t base, uint32_t feature){
    *(volatile uint32_t *)(base + HPM_PLIC_FEATURE_OFFSET) = feature;
}

/**
 * \brief 设置 PLIC（平台级中断控制器） 阈值
 *
 * \param[in] base      PLIC 基地址
 * \param[in] target    目标模式
 * \param[in] threshold 中断阈值
 */
__attribute__((always_inline)) static inline void __plic_set_threshold(uint32_t base,
                                                                       uint32_t target,
                                                                       uint32_t threshold){
    volatile uint32_t *p_threshold_ptr = (volatile uint32_t *)(base +
            HPM_PLIC_THRESHOLD_OFFSET +
            (target << HPM_PLIC_THRESHOLD_SHIFT_PER_TARGET));
    *p_threshold_ptr = threshold;
}

/**
 * \brief 完成中断
 *
 * \param[in] base   PLIC 基地址
 * \param[in] target 目标模式
 * \param[in] irq    中断号
 */
__attribute__((always_inline)) static inline void __plic_complete_irq(uint32_t base,
                                                                      uint32_t target,
                                                                      uint32_t irq){
    volatile uint32_t *p_claim_addr = (volatile uint32_t *)(base +
            HPM_PLIC_CLAIM_OFFSET +
            (target << HPM_PLIC_CLAIM_SHIFT_PER_TARGET));
    *p_claim_addr = irq;
}

/**
 * \brief 平台级中断控制器设置中断优先级
 */
__attribute__((always_inline)) static inline void __plic_irq_priority_set(uint32_t base,
                                                                          uint32_t irq_num,
                                                                          uint32_t priority){
    volatile uint32_t *p_priority_ptr =
            (volatile uint32_t *)(base + HPM_PLIC_PRIORITY_OFFSET +
                    ((irq_num - 1) << HPM_PLIC_PRIORITY_POS_PER_SOURCE));

    *p_priority_ptr = priority;
}

/**
 * \brief 平台级中断控制器中断使能
 */
__attribute__((always_inline)) static inline void __plic_irq_enable(uint32_t base,
                                                                    uint32_t target,
                                                                    uint32_t irq_num){
    volatile uint32_t *p_current_ptr =
            (volatile uint32_t *)(base + HPM_PLIC_TARGETINT_OFFSET +
            (target << HPM_PLIC_ENABLE_POS_PER_TARGET) +
            ((irq_num >> 5) << 2));
    uint32_t current = *p_current_ptr;

    current = current | (1 << (irq_num & 0x1F));

    *p_current_ptr = current;
}

/**
 * \brief 平台级中断控制器中断禁能
 */
__attribute__((always_inline)) static inline void __plic_irq_disable(uint32_t base,
                                                                     uint32_t target,
                                                                     uint32_t irq_num){
    volatile uint32_t *p_current_ptr =
            (volatile uint32_t *)(base + HPM_PLIC_TARGETINT_OFFSET +
            (target << HPM_PLIC_ENABLE_POS_PER_TARGET) +
            ((irq_num >> 5) << 2));
    uint32_t current = *p_current_ptr;

    current = current & ~((1 << (irq_num & 0x1F)));

    *p_current_ptr = current;
}

/**
 * \brief 中断处理函数注册
 *
 * \param[in] irq_num   要注册处理函数的中断号
 * \param[in] p_handler 中断处理函数
 * \param[in] p_arg     函数参数
 *
 * \retval 成功返回 0
 */
int intc_handler_register(uint32_t irq_num, pfn_irq_handler p_handler, void *p_arg);
/**
 * \brief 设置中断优先级
 *
 * \param[in] irq_num  中断号
 * \param[in] priority 中断优先级
 */
void intc_irq_priority_set(uint32_t irq_num, uint32_t priority);
/**
 * \brief 中断控制器中断使能函数
 *
 * \param[in] target  中断模式
 * \param[in] irq_num 中断号
 */
void intc_irq_enable(uint32_t target, uint32_t irq_num);
/**
 * \brief 中断控制器中断禁能函数
 *
 * \param[in] target  中断模式
 * \param[in] irq_num 中断号
 */
void intc_irq_disable(uint32_t target, uint32_t irq_num);
#endif

